/*
 * Copyright (c) 2008, University of Aarhus.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - Neither the name of the University of Aarhus nor the names
 *   of its contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author: Morten Tranberg Hansen <mth@cs.au.dk>
 * @date:   October 16 2008	
 * 
 */

package dk.sensobyg.base;

import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.LinkedList;
import java.util.TreeMap;
import java.util.HashMap;
import java.util.Date;

import org.apache.log4j.Logger;

public class Controller implements Collector, SensorNetwork, Admin {

	private transient static Logger log = Logger.getLogger("dk.sensobyg.base.Controller");
	
	private boolean running;
	private Database database;
	private SortedMap<Integer,AbstractWrapper> wrappers;
	private List<SensorListener> listeners;
	
	public Controller(Database database) {
		running = false;
		this.database = database;
		wrappers = new TreeMap<Integer,AbstractWrapper>();
		listeners = new LinkedList<SensorListener>();
	}
	
	public synchronized void start() {
		try {
			database.connect();
			for(AbstractWrapper w : wrappers.values()) {
				w.start();
			}
			running = true;
		} catch (DatabaseException e) {
			log.error("Could not close database.", e);
		}
	}
	
	public synchronized void stop() {
		running = false;
		for(AbstractWrapper w : wrappers.values()) {
			w.interrupt();
		}
		try {
			database.disconnect();
		} catch (DatabaseException e) {
			log.error("Could not close database.", e);
		}
	}
	
	/*************** COLLECTOR ***************/
	
	public void newData(SensorData data) {
		try {
			database.add(data);
		} catch (DatabaseException e) {
			log.error("Could not add new data to database.", e);
		}
	}

	/*************** ADMIN ***************/
	
	synchronized public int createWrapper(String configurationFile) {
		try {
			AbstractWrapper wrapper = WrapperFactory.createWrapper(this, configurationFile);
			if(running) wrapper.start();
			
			int id = 0;
			if(!wrappers.isEmpty()) id = wrappers.lastKey() + 1;
			wrappers.put(id, wrapper);
			return id;
		} catch(Exception e) {
			throw new IllegalArgumentException("Invalid configuration file.", e);
		}
	}
	
	synchronized public void configure(int wrapperId, Configuration configuration) throws IllegalArgumentException {
		AbstractWrapper wrapper = wrappers.get(wrapperId);		
		if(wrapper!=null) {
			wrapper.configure(configuration);
		} else {
			throw new IllegalArgumentException("Wrapper ID is out of range.");
		}
	}

	public Map<Integer,String> getWrappers() {
		Map<Integer,String> result = new HashMap<Integer,String>();
		for(Integer id : wrappers.keySet()) {
			result.put(id, wrappers.get(id).getName());
		}
		return result;
	}
	
	/*************** SENSORNETWORK ***************/
	
	public List<SensorData> get(Date start, Date end) {
		throw new UnsupportedOperationException("Not implemented!");
	}

	public SensorData getLatest(long sensorid) {
		List<SensorData> list = null;
		try {
			list = database.query(""+sensorid);
			if(!list.isEmpty()) {
				return list.get(0);
			}
		} catch (DatabaseException e) {
			log.error("Could not get data from database.", e);
		} 
		return null;
	}

	public void subscribe(SensorListener listener, long sensorid) {
		throw new UnsupportedOperationException("Not implemented!");
	}

	public void unsubscribe(SensorListener listener, long sensorid) {
		throw new UnsupportedOperationException("Not implemented!");		
	}
	
}
